package com.ruoyi.web.controller.system;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.ShiroConstants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.*;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.shiro.service.SysTokenService;
import com.ruoyi.framework.shiro.session.OnlineSession;
import com.ruoyi.system.service.ISysUserOnlineService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.framework.web.service.ConfigService;

/**
 * 登录验证
 *
 * @author ruoyi
 */
@Controller
public class SysLoginController extends BaseController {
    /**
     * 是否开启记住我功能
     */
    @Value("${shiro.rememberMe.enabled: false}")
    private boolean rememberMe;

    @Autowired
    private ConfigService configService;

    @Autowired
    private SysTokenService sysTokenService;

    @Autowired
    private ISysUserOnlineService sysUserOnlineService;

    /**
     * Session超时时间，单位为毫秒（默认30分钟）
     */
    @Value("${shiro.session.expireTime}")
    private int sessionExpireTime;

    /**
     * 登录页面
     *
     * @param request  HttpServletRequest对象
     * @param response HttpServletResponse对象
     * @param mmap     ModelMap对象，用于传递模型数据到视图
     * @return 登录页面视图名称
     */
    @GetMapping("/login")
    public String login(HttpServletRequest request, HttpServletResponse response, ModelMap mmap) {
        // 如果是Ajax请求，返回Json字符串。
        if (ServletUtils.isAjaxRequest(request)) {
            return ServletUtils.renderString(response, "{\"code\":\"1\",\"msg\":\"未登录或登录超时。请重新登录\"}");
        }
        // 是否开启记住我
        mmap.put("isRemembered", rememberMe);
        // 是否开启用户注册
        mmap.put("isAllowRegister", Convert.toBool(configService.getKey("sys.account.registerUser"), false));
        return "login";
    }


    /**
     * 处理AJAX登录请求，兼容API端的登录接口
     *
     * @param username   登录用户名
     * @param password   登录密码
     * @param rememberMe 是否记住用户（勾选"记住我"时为true）
     * @return 包含登录结果信息的AjaxResult对象（如成功状态、消息、数据等）
     */
    @PostMapping("/login")
    @ResponseBody
    public AjaxResult ajaxLogin(String username, String password, Boolean rememberMe) {
        // 获取isAPI
        String isAPI = getRequest().getHeader(ShiroConstants.IS_API_Key);
        String pass = password;
        // API请求: 处理密码为空的情况
        if (ShiroConstants.IS_API.equals(isAPI)) {
            // API请求: 密码为空，使用默认密码
            if (StringUtils.isEmpty(password)) {
                pass = UserConstants.DEFAULT_PASSWORD_FOR_API_USER;
            }

            // API请求: 默认不记住
            rememberMe = false;

            // API请求: 登录前先移除已存在的Token，确保每次登录都是新的
            sysTokenService.removeApiToken(username);
        }

        UsernamePasswordToken token = new UsernamePasswordToken(username, pass, rememberMe);
        Subject subject = SecurityUtils.getSubject();
        try {
            if (ShiroConstants.IS_API.equals(isAPI)) {
                // 清理缓存
//                SpringUtils.getBean(ISysUserOnlineService.class).removeUserCache(username, ShiroUtils.getSessionId());

                // 移除API Token
                sysTokenService.removeApiToken(username);

                // 处理API端登录重复登录有多个Session的问题
                if (subject.isAuthenticated()) {
//                    subject.logout();
                }

                // API请求: 删除用户所有会话
                sysUserOnlineService.deleteByLoginName(username);
            }

            // 登录认证
            subject.login(token);

            // API请求: 保存用户会话Session
            OnlineSession onlineSession = (OnlineSession) this.getRequest().getAttribute(ShiroConstants.ONLINE_SESSION);
            SysUser user = ShiroUtils.getSysUser();
            if (user != null && onlineSession != null && ShiroConstants.IS_API.equals(isAPI)) {
                onlineSession.setUserId(user.getUserId());
                onlineSession.setLoginName(user.getLoginName());
                onlineSession.setAvatar(user.getAvatar());
                onlineSession.setDeptName(user.getDept().getDeptName());
                onlineSession.markAttributeChanged();
                AsyncManager.me().execute(AsyncFactory.syncSessionToDb(onlineSession));
            }

            // 记录登录成功日志
//            AsyncManager.me().execute(AsyncFactory.recordLogininfor(user.getLoginName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));

            // API请求: 生成Token
            if (ShiroConstants.IS_API.equals(isAPI)) {
                // 生成Token
                String jwtToken = JwtShortTokenUtil.generateToken(username, sessionExpireTime * 30 * 1000);
                // 保存API Token
                sysTokenService.addApiToken(username, jwtToken);
                // 返回登录成功结果，包含Token
                return AjaxResult.success("登录成功").put("token", jwtToken);
            }

            // 普通请求：返回登录成功结果，包含Token
            return AjaxResult.success("登录成功");
        } catch (AuthenticationException e) {
            String msg = "用户或密码错误";
            if (StringUtils.isNotEmpty(e.getMessage())) {
                msg = e.getMessage();
            }
            // 记录登录失败日志
//            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
            return error(msg);
        }
    }

    /**
     * 用户登录API接口，用来给移动端提供登录API接口
     *
     * @param request  HttpServletRequest对象
     * @param response HttpServletResponse对象
     * @param username 用户名
     * @param password 密码
     * @return 包含生成的Token的响应结果
     */
    @PostMapping("/api/login")
    @Anonymous
    @ResponseBody
    public AjaxResult loginAPI(HttpServletRequest request, HttpServletResponse response, @RequestParam String username, @RequestParam String password) {
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            // 登录认证
            subject.login(token);
            // 生成Token
            String jwtToken = JwtShortTokenUtil.generateToken(username, sessionExpireTime * 1000);
            // 返回登录成功结果，包含Token
            return AjaxResult.success("登录成功").put("token", jwtToken);
        } catch (AuthenticationException e) {
            String msg = "用户名或密码错误";
            if (StringUtils.isNotEmpty(e.getMessage())) {
                msg = e.getMessage();
            }
            return error(msg);
        }
    }

    /**
     * 处理API注销请求
     *
     * @return 包含注销结果信息的AjaxResult对象
     */
    @PostMapping("/api/logout")
    @Anonymous
    @ResponseBody
    public AjaxResult apiLogout(@RequestParam String username) {
        // 检查Token是否有效
        String token = getAPIToken();
        boolean isTokenValid = checkAPITokenValid(token);
        if (!isTokenValid && !sysTokenService.existsApiToken(token)) {
            return error("API Token无效或用户已经注销");
        }

        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            // 获取当前用户
            SysUser user = ShiroUtils.getSysUser();
            if (user != null) {
                // 记录注销日志
                AsyncManager.me().execute(AsyncFactory.recordLogininfo(user.getLoginName(), Constants.LOGOUT, MessageUtils.message("user.logout.success")));
            }
            // 执行注销
            subject.logout();
            // 移除API Token
            sysTokenService.removeApiToken(username);
            // 返回注销成功结果
            return AjaxResult.success("注销成功");
        }
        return AjaxResult.success("注销失败");
    }

    /**
     * 未授权页面
     * 娃
     *
     * @return 未授权页面视图名称
     */
    @GetMapping("/unauth")
    public String unauth() {
        return "error/unauth";
    }


    @GetMapping("/tokenCacheTest")
    @ResponseBody
    public AjaxResult tokenCacheTest() {
        String userID = "admin";
        String token = sysTokenService.getApiToken(userID);

        String token1 = "22ddddd222333";
        sysTokenService.addApiToken(userID, token1);

        String token2 = "testhhdhdndhdhd";
        sysTokenService.addApiToken(userID, token2);

        token = sysTokenService.getApiToken(userID);

        sysTokenService.removeApiToken(userID);
        token = sysTokenService.getApiToken(userID);

        return AjaxResult.success("测试完成！");
    }
}
